﻿using System.Collections.Generic;
using System.Linq;
using Microsoft.SharePoint.Client;
using Sources;
using System.ComponentModel;
using DeploySources.Helper;
using DeploySources.MVVM;
using System.Windows;

namespace DeploySources.ViewModel
{
	/// <summary>
	/// ViewModel for the WorkerView
	/// </summary>
	public class WorkerViewModel : BaseViewModel
	{
		private readonly BackgroundWorker _worker;
		private readonly Window _view;

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="context">SharePoint context</param>
		/// <param name="itemsToDeploy">Items to deploy</param>
		/// <param name="view">View for the ViewModel</param>
		public WorkerViewModel(ClientContext context, IEnumerable<IDeployableObject> itemsToDeploy, Window view)
		{
			_view = view;

			_worker = new BackgroundWorker
			{
				WorkerReportsProgress = true,
				WorkerSupportsCancellation = true
			};

			_worker.DoWork += WorkerDoWork;
			_worker.ProgressChanged += WorkerProgressChanged;
			_worker.RunWorkerCompleted += WorkerRunWorkerCompleted;

			var args = new WorkerArgument { Context = context, Objects = itemsToDeploy };

			_worker.RunWorkerAsync(args);
		}

		private int _itemCount;
		/// <summary>
		/// Total Count of all deployable objects
		/// </summary>
		public int ItemCount
		{
			get	{ return _itemCount; }
			set
			{
				_itemCount = value;
				OnPropertyChanged("ItemCount");
			}
		}

		private int _currentValue;
		/// <summary>
		/// Current item index which gets deployed
		/// </summary>
		public int CurrentValue
		{
			get { return _currentValue; }
			set
			{
				_currentValue = value;
				OnPropertyChanged("CurrentValue");
			}
		}

		private string _currentItem;
		/// <summary>
		/// Current item name which gets deployed
		/// </summary>
		public string CurrentItem
		{
			get { return _currentItem; }
			set
			{
				_currentItem = value;
				OnPropertyChanged("CurrentItem");
			}
		}

		/// <summary>
		/// Entry Point for the async worker
		/// </summary>
		/// <param name="sender">Sender</param>
		/// <param name="e">Worker arguments</param>
		private void WorkerDoWork(object sender, DoWorkEventArgs e)
		{
			var context = (e.Argument as WorkerArgument).Context;
			var items = (e.Argument as WorkerArgument).Objects;

			var deployableObjects = items as IDeployableObject[] ?? items.ToArray();

			_worker.ReportProgress(0, deployableObjects.Length);
			
			for (var i = 0; i < deployableObjects.Length; i++)
			{
				var item = deployableObjects.ElementAt(i);

				if (item is FieldArtefact)
				{
					var artefact = item as FieldArtefact;
					_worker.ReportProgress(1, new ProgressReportArgument { Index = i, Name = artefact.Name });
					EnsureData.EnsureField(context, item as FieldArtefact);
				}
				else if (item is ContentTypeArtefact)
				{
					var artefact = item as ContentTypeArtefact;
					_worker.ReportProgress(1, new ProgressReportArgument { Index = i, Name = artefact.Name });
					EnsureData.EnsureContentType(context, item as ContentTypeArtefact);
				}
				else if (item is ListArtefact)
				{
					var artefact = item as ListArtefact;
					_worker.ReportProgress(1, new ProgressReportArgument { Index = i, Name = artefact.Title });
					EnsureData.EnsureList(context, item as ListArtefact);
				}
			}
		}

		/// <summary>
		/// Handle process reports for the async worker to actualize the ui
		/// </summary>
		/// <param name="sender">Sender</param>
		/// <param name="e">Worker arguments</param>
		private void WorkerProgressChanged(object sender, ProgressChangedEventArgs e)
		{
			if (e.ProgressPercentage == 0)
			{
				ItemCount = (int)e.UserState;
			}
			else if (e.ProgressPercentage == 1)
			{
				var report = (ProgressReportArgument) e.UserState;
				CurrentValue = report.Index;
				CurrentItem = report.Name;
			}
		}

		/// <summary>
		/// Handle end of the async process
		/// </summary>
		/// <param name="sender">Sender</param>
		/// <param name="e">Worker arguments</param>
		private void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
		{
			CurrentValue = ItemCount;
			_view.Close();
		}
	}
}
